<!-- AI生成报告组件 -->
<template>
  <el-popover
    popper-class="!rounded-16px !px-18px"
    placement="bottom-end"
    trigger="click"
    v-model:visible="popoverVisible"
    :width="getViewportPx(784)"
    :show-arrow="false"
    :offset="parseInt(getViewportPx(8, true))"
    @hide="closePopver"
    @show="onPopverShow"
  >
    <template #reference>
      <el-button
        color="#626aef"
        class="bg-[linear-gradient(180deg,#00cde2_0%,#69f0ff_100%)] !border-0 !fw-400"
        >生成报告</el-button
      >
    </template>
    <div class="h-760px max-w-80vw" v-loading="loading" element-loading-text="加载中...">
      <div>
        <el-scrollbar ref="messageRef" :height="getViewportPx(706)">
          <div
            class="!min-h-100%"
            :style="{
              height: scrollMaxTop + 'px'
            }"
          >
            <Typewriter
              :content="receiveMessageFullText"
              isMarkdown
              typing
              @writing="scrollToBottom()"
            />
          </div>
        </el-scrollbar>
      </div>

      <div class="w-full flex justify-end items-center mt-16px">
        <el-button
          color="#626aef"
          class="bg-[linear-gradient(180deg,#00cde2_0%,#33E7FA_100%)] !border-0 !fw-400"
          @click="copy(receiveMessageFullText)"
        >
          复制
        </el-button>
        <el-button @click="popoverVisible = false">关闭</el-button>
      </div>
    </div>
  </el-popover>
</template>
<script setup lang="ts">
import { Typewriter } from 'vue-element-plus-x'
import { useClipboard } from '@vueuse/core'
import { ChatMessageApi, ChatMessageVO } from '@/api/ai/chat/message'
import { ChatConversationApi, ChatConversationVO } from '@/api/ai/chat/conversation'
import { getViewportPx } from '@/utils/formatter'
import '@/styles/markdown/index.scss'
import { isObject } from '@/utils/is'

interface saveOV {
  roleId: string
  content?: string
}

const props = defineProps<{
  roleId: string | number
  sendContent: string | object
}>()

const message = useMessage()
const { t } = useI18n() // 国际化

const popoverVisible = ref(false)
const loading = ref(false)
const activeConversationId = ref<number | null>(null)
const conversationInAbortController = ref<AbortController | null>(null)
const receiveMessageFullText = ref('')
const messageRef = ref()
const isFinish = ref(false) // SSE是否完成

const ChatConversationIdKey = 'chartChatConversationIdKey'
const curContent = ref<any>({})

const scrollMaxTop = ref(parseInt(getViewportPx(676, true)))

// 复制
const copy = async (textToCopy: string) => {
  if (!isFinish.value) {
    message.warning('生成中,请稍后复制。')
    return
  }
  const { copy, copied, isSupported } = useClipboard({ source: textToCopy })
  if (!isSupported) {
    message.error(t('common.copyError'))
  } else {
    await copy()
    if (unref(copied)) {
      message.success(t('common.copySuccess'))
    }
  }
}
// 停止SSE
const stopStream = async () => {
  // tip：如果 stream 进行中的 message，就需要调用 controller 结束
  if (conversationInAbortController.value) {
    conversationInAbortController.value.abort()
  }
  loading.value = false
}

// 滚动到底部
const scrollToBottom = async () => {
  // await nextTick()
  if (messageRef.value) {
    const scrollHeight = messageRef.value.wrapRef.scrollHeight
    if (scrollMaxTop.value < scrollHeight) {
      scrollMaxTop.value = scrollHeight
      messageRef.value!.scrollTo({
        top: scrollHeight,
        behavior: 'smooth'
      })
    }
  }
}
// 发送消息
const doSendMessageStream = async (userMessage: ChatMessageVO) => {
  // 创建 AbortController 实例，以便中止请求
  conversationInAbortController.value = new AbortController()
  try {
    isFinish.value = false
    await ChatMessageApi.sendChatMessageStream(
      {
        conversationId: userMessage.conversationId,
        content: userMessage.content,
        useContext: false
      },
      conversationInAbortController.value,
      async (res) => {
        loading.value = false
        const { code, data, msg } = JSON.parse(res.data)
        if (code !== 0) {
          message.alert(`对话异常! ${msg}`)
          localStorage.removeItem(ChatConversationIdKey)
          return
        }
        // 如果内容为空，就不处理。
        if (data.receive.content === '') {
          return
        }
        receiveMessageFullText.value = receiveMessageFullText.value + data.receive.content
      },
      (error) => {
        message.alert(`对话异常! ${error}`)
        localStorage.removeItem(ChatConversationIdKey)
        stopStream()
        // 需要抛出异常，禁止重试
        throw error
      },
      () => {
        isFinish.value = true
        stopStream()
      }
    )
  } catch {}
}
// 创建对话
const createChatConversation = async ({ roleId, content = '' }: saveOV) => {
  if (receiveMessageFullText.value && curContent.value[roleId] === content) {
    return
  }
  receiveMessageFullText.value = ''
  curContent.value[roleId] = content
  loading.value = true
  if (!activeConversationId.value) {
    // 1. 新建对话
    try {
      activeConversationId.value = await ChatConversationApi.createChatConversationMy({
        roleId
      } as unknown as ChatConversationVO)
    } catch (error) {
      loading.value = false
    }
  }
  doSendMessageStream({ conversationId: activeConversationId.value, content } as ChatMessageVO)
}

// 关闭对话框
const closePopver = () => {
  if (!isFinish.value) {
    receiveMessageFullText.value = ''
  }
  scrollMaxTop.value = parseInt(getViewportPx(676, true))
  stopStream()
}
// 显示Popver回调
const onPopverShow = () => {
  createChatConversation({
    roleId: props.roleId?.toString(),
    content: isObject(props.sendContent)
      ? JSON.stringify(props.sendContent)
      : (props.sendContent as string)
  })
}
</script>
